package com.zycfc.zsf.boot.job.core;

import com.dangdang.ddframe.job.lite.config.*;
import com.dangdang.ddframe.job.reg.base.*;
import com.dangdang.ddframe.job.executor.*;
import com.dangdang.ddframe.job.event.*;
import com.dangdang.ddframe.job.lite.api.strategy.*;
import com.dangdang.ddframe.job.lite.internal.guarantee.*;
import com.dangdang.ddframe.job.lite.api.listener.*;
import com.dangdang.ddframe.job.api.script.*;
import com.google.common.base.*;
import com.dangdang.ddframe.job.api.*;
import org.quartz.impl.*;
import com.dangdang.ddframe.job.exception.*;
import org.quartz.*;
import org.quartz.simpl.*;
import com.dangdang.ddframe.job.lite.internal.schedule.*;
import org.slf4j.*;
import java.util.*;

public class ZsfJobScheduler
{
    private static final Logger log;
    public static final String ELASTIC_JOB_DATA_MAP_KEY = "elasticJob";
    private static final String JOB_FACADE_DATA_MAP_KEY = "jobFacade";
    private final LiteJobConfiguration liteJobConfig;
    private final CoordinatorRegistryCenter regCenter;
    private final SchedulerFacade schedulerFacade;
    private final JobFacade jobFacade;
    
    public ZsfJobScheduler(final CoordinatorRegistryCenter regCenter, final LiteJobConfiguration liteJobConfig, final ElasticJobListener... elasticJobListeners) {
        this(regCenter, liteJobConfig, new JobEventBus(), elasticJobListeners);
    }
    
    public ZsfJobScheduler(final CoordinatorRegistryCenter regCenter, final LiteJobConfiguration liteJobConfig, final JobEventConfiguration jobEventConfig, final ElasticJobListener... elasticJobListeners) {
        this(regCenter, liteJobConfig, new JobEventBus(jobEventConfig), elasticJobListeners);
    }
    
    private ZsfJobScheduler(final CoordinatorRegistryCenter regCenter, final LiteJobConfiguration liteJobConfig, final JobEventBus jobEventBus, final ElasticJobListener... elasticJobListeners) {
        JobRegistry.getInstance().addJobInstance(liteJobConfig.getJobName(), new JobInstance());
        this.liteJobConfig = liteJobConfig;
        this.regCenter = regCenter;
        final List<ElasticJobListener> elasticJobListenerList = Arrays.asList(elasticJobListeners);
        this.setGuaranteeServiceForElasticJobListeners(regCenter, elasticJobListenerList);
        this.schedulerFacade = new SchedulerFacade(regCenter, liteJobConfig.getJobName(), (List)elasticJobListenerList);
        this.jobFacade = (JobFacade)new LiteJobFacade(regCenter, liteJobConfig.getJobName(), (List)Arrays.asList(elasticJobListeners), jobEventBus);
    }
    
    private void setGuaranteeServiceForElasticJobListeners(final CoordinatorRegistryCenter regCenter, final List<ElasticJobListener> elasticJobListeners) {
        final GuaranteeService guaranteeService = new GuaranteeService(regCenter, this.liteJobConfig.getJobName());
        for (final ElasticJobListener each : elasticJobListeners) {
            if (each instanceof AbstractDistributeOnceElasticJobListener) {
                ((AbstractDistributeOnceElasticJobListener)each).setGuaranteeService(guaranteeService);
            }
        }
    }
    
    public void init() {
        final LiteJobConfiguration liteJobConfigFromRegCenter = this.schedulerFacade.updateJobConfiguration(this.liteJobConfig);
        JobRegistry.getInstance().setCurrentShardingTotalCount(liteJobConfigFromRegCenter.getJobName(), liteJobConfigFromRegCenter.getTypeConfig().getCoreConfig().getShardingTotalCount());
        final JobScheduleController jobScheduleController = new JobScheduleController(this.createScheduler(), this.createJobDetail(liteJobConfigFromRegCenter.getTypeConfig().getJobClass()), liteJobConfigFromRegCenter.getJobName());
        JobRegistry.getInstance().registerJob(liteJobConfigFromRegCenter.getJobName(), jobScheduleController, this.regCenter);
        this.schedulerFacade.registerStartUpInfo(!liteJobConfigFromRegCenter.isDisabled());
        jobScheduleController.scheduleJob(liteJobConfigFromRegCenter.getTypeConfig().getCoreConfig().getCron());
    }
    
    private JobDetail createJobDetail(final String jobClass) {
        final JobDetail result = JobBuilder.newJob((Class)LiteJob.class).withIdentity(this.liteJobConfig.getJobName()).build();
        result.getJobDataMap().put("jobFacade", (Object)this.jobFacade);
        final Optional<ElasticJob> elasticJobInstance = this.createElasticJobInstance();
        if (elasticJobInstance.isPresent()) {
            result.getJobDataMap().put("elasticJob", elasticJobInstance.get());
        }
        else if (!jobClass.equals(ScriptJob.class.getCanonicalName())) {
            try {
                result.getJobDataMap().put("elasticJob", (Object)Class.forName(jobClass).newInstance());
            }
            catch (ReflectiveOperationException ex) {
                throw new JobConfigurationException("Elastic-Job: Job class '%s' can not initialize.", new Object[] { jobClass });
            }
        }
        return result;
    }
    
    protected Optional<ElasticJob> createElasticJobInstance() {
        return (Optional<ElasticJob>)Optional.absent();
    }
    
    private Scheduler createScheduler() {
        Scheduler result;
        try {
            final StdSchedulerFactory factory = new StdSchedulerFactory();
            factory.initialize(this.getBaseQuartzProperties());
            result = factory.getScheduler();
            result.getListenerManager().addTriggerListener((TriggerListener)this.schedulerFacade.newJobTriggerListener());
        }
        catch (SchedulerException ex) {
            throw new JobSystemException((Throwable)ex);
        }
        return result;
    }
    
    private Properties getBaseQuartzProperties() {
        final Properties result = new Properties();
        ((Hashtable<String, String>)result).put("org.quartz.threadPool.class", SimpleThreadPool.class.getName());
        ((Hashtable<String, String>)result).put("org.quartz.threadPool.threadCount", "4");
        ((Hashtable<String, String>)result).put("org.quartz.threadPool.threadPriority", "5");
        ((Hashtable<String, String>)result).put("org.quartz.scheduler.instanceName", this.liteJobConfig.getJobName());
        ((Hashtable<String, String>)result).put("org.quartz.jobStore.misfireThreshold", "1");
        ((Hashtable<String, String>)result).put("org.quartz.plugin.shutdownhook.class", JobShutdownHookPlugin.class.getName());
        ((Hashtable<String, String>)result).put("org.quartz.plugin.shutdownhook.cleanShutdown", Boolean.TRUE.toString());
        return result;
    }
    
    public SchedulerFacade getSchedulerFacade() {
        return this.schedulerFacade;
    }
    
    static {
        log = LoggerFactory.getLogger((Class)ZsfJobScheduler.class);
    }
}
